<template>
  <div class="vue-container">
    <el-dialog
      ref="maxDialog"
      v-drag
      :title="ruleForm.id ? '编辑部门' : '新增部门'"
      :visible.sync="dialogVisible"
      width="450px"
      @closed="closedDialog"
    >
      <el-form
        ref="reform"
        v-loading="loading"
        :model="ruleForm"
        status-icon
        :rules="rules"
        :size="size"
        label-width="90px"
        :show-message="showMessage"
        element-loading-background="rgba(255, 255, 255, 0.8)"
        element-loading-text="数据正在加载中"
        element-loading-spinner="el-icon-loading"
      >
        <el-form-item v-if="ruleForm.parentId !== '0'" label="上级部门" prop="parentId">
          <treeselect
            v-if="!ruleForm.parentName"
            ref="treeselect"
            :key="refreshKey"
            v-model="ruleForm.parentId"
            :options="options"
            :async="isAsync"
            :normalizer="normalizer"
            :load-options="isAsync ? asyncOptions : loadOptions"
            :multiple="false"
            :class="size"
            placeholder="选择上级部门"
            no-options-text="暂无可用选项"
            no-children-text="数据加载中"
            loading-text="数据加载中"
            no-results-text="暂无数据"
            search-prompt-text="正在搜索"
            @keydown.native="treeKeydown"
            @open="itemopen"
            @select="handleSelect"
          />
          <el-input v-else v-model="ruleForm.parentName" :disabled="true" />
        </el-form-item>
        <el-form-item label="部门名称" prop="name">
          <el-input v-model.trim="ruleForm.name" placeholder="请输入部门名称" type="text" show-word-limit autocomplete="off" />
        </el-form-item>
        <el-form-item label="部门状态" prop="status">
          <el-radio-group v-model="ruleForm.status">
            <el-radio v-for="(item, index) in obj.statusList" :key="index" :label="Number(item.code)">
              {{ item.label }}
            </el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="排序" prop="sort">
          <el-input-number v-model.trim="ruleForm.sort" :min="0" placeholder="请输入排序" style="width: 100%;" />
        </el-form-item>
        <el-form-item label="部门备注" prop="remarks">
          <el-input
            v-model.trim="ruleForm.remarks"
            placeholder="请输入部门备注"
            type="textarea"
            :rows="4"
            show-word-limit
            autocomplete="off"
          />
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button :size="size" @click="dialogVisible = false">取消</el-button>
        <el-button v-throttle :size="size" :loading="loading" type="primary" @click="submitForm">确定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import { mixin } from '@/views/pages/mixin/save'
export default {
  name: 'DepartmentSave',
  mixins: [mixin],
  data() {
    const that = this
    return {
      // 表单对象
      ruleForm: {
        status: 1,
        sort: 0
      },
      // 树数据
      options: [],
      // 是否异步搜索
      isAsync: false,
      // 刷新树
      refreshKey: 0,
      // 树参数结构转换
      normalizer(node) {
        return {
          label: node.name,
          parentId: node.parentId,
          isLeaf: node.isLeaf,
          isDisabled: node.id === that.ruleForm.id
        }
      },
      // 表单校验
      rules: {
        parentId: [{ required: true, message: '请选择上级部门', trigger: 'change' }],
        name: [{ required: true, message: '请输入部门名称', trigger: 'change' }],
        status: [{ required: true, message: '请选择部门状态', trigger: 'change' }],
        sort: [{ required: true, message: '请输入排序', trigger: 'change' }]
      },
      // 计时器
      inval: null,
      // 加载子节点后储存对象
      loadMap: {},
      // 父节点数组
      parentIds: [],
      // 计算每次展开接口的响应时间
      duration: 50
    }
  },
  watch: {
    'ruleForm.parentId': {
      handler(val) {
        // 若值被清空且在非打开弹窗初始化情况下
        if (!val && Object.keys(this.loadMap).length) {
          this.createTree()
        }
      },
      deep: true
    }
  },
  beforeDestroy() {
    if (this.inval) clearInterval(this.inval)
  },
  methods: {
    // 弹出窗口加载
    openDialog(rows) {
      this.dialogVisible = true
      if (this.obj.arr && this.obj.arr.length) {
        this.options = [...this.obj.arr]
        this.refreshKey += 1
      }
      if (rows) {
        // 将当前子节点的父节点做备份保存，方便更改后对两个节点进行刷新
        rows.startParentId = rows.parentId
        this.ruleForm = { ...this.ruleForm, ...rows }
        if (rows.parentId && !rows.parentName) {
          this.loadToCurrent(rows.parentId)
        }
      }
    },
    // 树按键监听
    treeKeydown() {
      this.isAsync = true
    },
    // 树下拉打开监听
    itemopen() {
      if (this.isAsync) this.createTree()
    },
    // 初始赋值
    createTree() {
      // 若打开/收起时未选择异步搜索结果，关闭异步搜索并重置树数据
      this.isAsync = false
      // 树重新赋值
      this.options = [...this.obj.arr]
      this.$nextTick(() => {
        if (this.ruleForm.parentId) this.loadToCurrent(this.ruleForm.parentId)
      })
    },
    // 懒加载找到当前选中节点
    loadToCurrent(id) {
      this.loading = true
      if (this.parentIds && this.parentIds.length) {
        this.nodeTree(this.parentIds)
      } else {
        // 树懒加载数据回显
        this.funs['parentIds'](id).then(async res => {
          this.parentIds = res.data || []
          this.nodeTree(res.data || [])
        }).catch(() => {
          this.loading = false
        })
      }
    },
    // 计时加载每一个父节点
    nodeTree(data) {
      if (data.length) {
        let i = 0
        let count = 0
        // 针对需要回显的节点进行计时默认展开，计时时间为每次请求接口的响应时间
        this.inval = setInterval(() => {
          count++
          // 若计时次数超过100停止计时，返回数据错误提示
          if (count > 100) {
            clearInterval(this.inval)
            this.$message.error('数据错误，计时超时')
            this.loading = false
            return
          }
          const node = this.$refs.treeselect.getNode(data[i])
          // 若取不到nestedSearchLabel说明节点未渲染完毕
          if (node.nestedSearchLabel) {
            node.isExpanded = true
            // 调用loadChildrenOptions进行节点展开后的数据渲染
            this.$refs.treeselect.loadChildrenOptions({ ...node })
            i += 1
            if (i >= data.length) {
              // 关闭计时器
              clearInterval(this.inval)
              this.loading = false
            }
          }
        }, this.duration)
      } else {
        this.loading = false
      }
    },
    // 树懒加载
    async loadOptions({ arr, parentNode }) {
      if (arr) {
        this.options = this.getData(arr)
      } else {
        const startTime = new Date().getTime()
        if (!(parentNode.id in this.loadMap)) {
          const res = await this.funs['list']({ parentId: parentNode.id })
          this.duration = (new Date().getTime() + 50) - startTime
          this.$set(parentNode, 'children', this.getData(res.data))
          this.loadMap[parentNode.id] = this.getData(res.data)
        } else {
          this.duration = 50
        }
        this.$set(parentNode, 'children', this.loadMap[parentNode.id])
      }
    },
    // 远程搜索
    asyncOptions({ searchQuery, callback }) {
      this.funs['list']({ keyword: searchQuery }).then(res => {
        const options = this.getData(res.data, false)
        callback(null, options)
      })
    },
    // 懒加载及异步搜索数据处理
    getData(data, isLeaf = true) {
      return data.length ? data.map(option => {
        const obj = {
          id: option.id,
          name: option.name,
          parentId: option.parentId,
          isLeaf: option.isLeaf
        }
        if (!option.isLeaf && isLeaf) {
          obj.children = null
        }
        return obj
      }) : []
    },
    // 上级部门选中触发
    handleSelect(e) {
      if (this.isAsync) {
        this.isAsync = false
        this.loadOptions({ arr: [e] })
      }
      // 设置选中值的父id
      this.ruleForm.endParentId = e.isLeaf ? e.parentId : e.id
    },
    // 弹窗关闭动画结束触发
    closedDialog() {
      this.ruleForm = { status: 1, sort: 0 }
      this.$refs.reform.resetFields()
      this.parentIds = []
      this.loadMap = {}
      if (this.inval) clearInterval(this.inval)
    }
  }
}
</script>
